home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / upc12bs1.zip / UUCP / uux.c < prev    next >
C/C++ Source or Header  |  1993-10-03  |  43KB  |  1,224 lines

  1. /*--------------------------------------------------------------------*/
  2. /*          u u x . c                                                 */
  3. /*                                                                    */
  4. /*          Queue remote commands for UUCP under UUPC/extended        */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*       Changes Copyright (c) 1989-1993 by Kendra Electronic         */
  9. /*       Wonderworks.                                                 */
  10. /*                                                                    */
  11. /*       All rights reserved except those explicitly granted by       */
  12. /*       the UUPC/extended license agreement.                         */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: uux.c 1.8 1993/10/03 20:43:08 ahd Exp $
  21.  *
  22.  *    Revision history:
  23.  *    $Log: uux.c $
  24.  * Revision 1.8  1993/10/03  20:43:08  ahd
  25.  * Normalize comments to C++ double slash
  26.  *
  27.  * Revision 1.7  1993/10/01  01:17:44  ahd
  28.  * Additional correct from Richard Gumpertz
  29.  *
  30.  * Revision 1.6  1993/09/28  01:38:19  ahd
  31.  * Corrections from Robert H. Gumpertz (rhg@cps.com)
  32.  *
  33.  * Revision 1.5  1993/09/20  04:48:25  ahd
  34.  * TCP/IP support from Dave Watt
  35.  * 't' protocol support
  36.  * OS/2 2.x support (BC++ 1.0 for OS/2)
  37.  *
  38.  */
  39.  
  40. /*
  41.       Program:    uux.c              27 August 1991
  42.       Author:     Mitch Mitchell
  43.       Email:      mitch@harlie.lonestar.org
  44.  
  45.       Much of this code is shamelessly taken from extant code in
  46.       UUPC/Extended.
  47.  
  48.       Usage:      uux [ options ] command-string
  49.  
  50.                Where [ options ] are:
  51.  
  52.      -aname    Use name as the user identification replacing the initiator
  53.                user-id.  (Notification will be returned to the user.)
  54.  
  55.      -b        Return whatever standard input was provided to the uux command
  56.                if the exit status is non-zero.
  57.  
  58.      -c        Do not copy local file to the spool directory for transfer to
  59.                the remote machine (default).
  60.  
  61.      -C        Force the copy of local files to the spool directory for
  62.                transfer.
  63.  
  64.      -e        Remote system should use sh to execute commands.
  65.  
  66.      -E        Remote system should use exec to execute commands.
  67.  
  68.      -ggrade   Grade is a single letter/number; lower ASCII sequence
  69.                characters will cause the job to be transmitted earlier during
  70.                a particular conversation.
  71.  
  72.      -j        Output the jobid ASCII string on the standard output which is
  73.                the job identification.  This job identification can be used by
  74.                uustat to obtain the status or terminate a job.
  75.  
  76.      -n        Do not notify the user if the command fails.
  77.  
  78.      -p        The standard input to uux is made the standard input to the
  79.                command-string.
  80.  
  81.      -r        Do not start the file transfer, just queue the job.
  82.                (Currently uux does not attempt to start the transfer
  83.                 regardless of the presense of this option).
  84.  
  85.      -sfile    Report status of the transfer in file.
  86.  
  87.      -xdebug_level
  88.                Produce debugging output on the standard output.  The
  89.                debug_level is a number between 0 and ??; higher numbers give
  90.                more detailed information.
  91.  
  92.      -z        Send success notification to the user.
  93.  
  94.  
  95.       The command-string is made up of one or more arguments that
  96.       look like a normal command line, except that the command and
  97.       filenames may be prefixed by system-name!.  A null
  98.       system-name is interpreted as the local system.
  99.  
  100. */
  101.  
  102. /*--------------------------------------------------------------------*/
  103. /*         System include files                                       */
  104. /*--------------------------------------------------------------------*/
  105.  
  106. #include <stdio.h>
  107. #include <io.h>
  108. #include <string.h>
  109. #include <time.h>
  110. #include <stdlib.h>
  111. #include <fcntl.h>
  112. #include <sys/types.h>
  113. #include <sys/stat.h>
  114.  
  115. #ifdef _Windows
  116. #include <windows.h>
  117. #endif
  118.  
  119. /*--------------------------------------------------------------------*/
  120. /*         Local include files                                        */
  121. /*--------------------------------------------------------------------*/
  122.  
  123. #include  "lib.h"
  124. #include  "hlib.h"
  125. #include  "getopt.h"
  126. #include  "getseq.h"
  127. #include  "expath.h"
  128. #include  "import.h"
  129. #include  "pushpop.h"
  130. #include  "security.h"
  131. #include  "hostable.h"
  132. #include  "timestmp.h"
  133.  
  134. #ifdef _Windows
  135. #include "winutil.h"
  136. #include "logger.h"
  137. #endif
  138.  
  139. /*--------------------------------------------------------------------*/
  140. /*        Define current file name for panic() and printerr()         */
  141. /*--------------------------------------------------------------------*/
  142.  
  143. currentfile();
  144.  
  145. /*--------------------------------------------------------------------*/
  146. /*                          Global variables                          */
  147. /*--------------------------------------------------------------------*/
  148.  
  149. typedef enum {
  150.           FLG_USE_USERID,
  151.           FLG_OUTPUT_JOBID,
  152.           FLG_READ_STDIN,
  153.           FLG_QUEUE_ONLY,
  154.           FLG_NOTIFY_SUCCESS,
  155.           FLG_NONOTIFY_FAIL,
  156.           FLG_COPY_SPOOL,
  157.           FLG_RETURN_STDIN,
  158.           FLG_STATUS_FILE,
  159.           FLG_USE_EXEC,
  160.           FLG_MAXIMUM
  161.        } UuxFlags;
  162.  
  163. typedef enum {
  164.       DATA_FILE   = 0,        // Normal data file passed argument
  165.       INPUT_FILE  = 1,        // Redirected stdin file
  166.       OUTPUT_FILE = 2         // Redirected stdout file
  167.       } FileType;
  168.  
  169. static boolean flags[FLG_MAXIMUM] = {
  170.                                         FALSE,
  171.                                         FALSE,
  172.                                         FALSE,
  173.                                         FALSE,
  174.                                         FALSE,
  175.                                         FALSE,
  176.                                         FALSE,
  177.                                         FALSE,
  178.                                         FALSE,
  179.                                         FALSE
  180.                                     };
  181. static char* st_out = NULL;
  182. static char* user_id = NULL;
  183. static char  grade = 'Z';          // Default grade of service
  184.  
  185. static char  job_id[15];
  186.  
  187. static char* spool_fmt = SPOOLFMT;
  188. static char* dataf_fmt = DATAFFMT;
  189.  
  190. static char* send_cmd  = "S %s %s %s - %s 0666\n";
  191.  
  192. /*--------------------------------------------------------------------*/
  193. /*                        Internal prototypes                         */
  194. /*--------------------------------------------------------------------*/
  195.  
  196. void main(int  argc, char  **argv);
  197. static void usage( void );
  198. static char *SwapSlash(char *p);
  199. static boolean cp(char *from, char *to);
  200. static boolean split_path(char *path,
  201.                           char *system,
  202.                           char *file,
  203.                           boolean expand,
  204.                           char *default_sys);
  205. static boolean CopyData( const char *input, const char *output);
  206.  
  207. static boolean do_uuxqt(char *job_name, char *src_syst, char *src_file, char *dest_syst, char *dest_file);
  208.  
  209. static boolean do_copy(char *src_syst, char *src_file, char *dest_syst, char *dest_file);
  210.  
  211. static boolean do_remote(int optind, int argc, char **argv);
  212. static void preamble(FILE* stream);
  213. static char subseq( void );
  214.  
  215. /*--------------------------------------------------------------------*/
  216. /*    u s a g e                                                       */
  217. /*                                                                    */
  218. /*    Report flags used by program                                    */
  219. /*--------------------------------------------------------------------*/
  220.  
  221. static void usage()
  222. {
  223.       fprintf(stderr, "Usage: uux\t[-c|-C] [-e|-E] [-b] [-gGRADE] "
  224.                       "[-p] [-j] [-n] [-r] [-sFILE]\\\n"
  225.                       "\t\t[-aNAME] [-z] [-] [-xDEBUG_LEVEL] "
  226.                       "command-string\n");
  227. }
  228.  
  229.  
  230. /*--------------------------------------------------------------------*/
  231. /*    s w a p s l a s h                                               */
  232. /*                                                                    */
  233. /*    Change backslash in a directory path to forward slash           */
  234. /*--------------------------------------------------------------------*/
  235.  
  236. static char *SwapSlash(char *p)
  237. {
  238.      char *q = p;
  239.  
  240.      while (*q) {
  241.         if (*q ==  '\\')
  242.            *q = '/';
  243.         q++;
  244.      }
  245.      return p;
  246. };
  247.  
  248. /*--------------------------------------------------------------------*/
  249. /*    c p                                                             */
  250. /*                                                                    */
  251. /*    Copy Local Files                                                */
  252. /*--------------------------------------------------------------------*/
  253.  
  254. static boolean cp(char *from, char *to)
  255. {
  256.       int  fd_from, fd_to;
  257.       int  nr;
  258.       int  nw = -1;
  259.       char buf[BUFSIZ];            // faster if we alloc a big buffer
  260.  
  261.       /* This would be even faster if we determined that both files
  262.          were on the same device, dos >= 3.0, and used the dos move
  263.          function */
  264.  
  265.       if ((fd_from = open(from, O_RDONLY | O_BINARY)) == -1)
  266.          return FALSE;        // failed
  267.  
  268.       /* what if the to is a directory? */
  269.       /* possible with local source & dest uucp */
  270.  
  271.       if ((fd_to = open(to, O_CREAT | O_BINARY | O_WRONLY, S_IWRITE | S_IREAD)) == -1) {
  272.          close(fd_from);
  273.          return FALSE;        // failed
  274.          /* NOTE - this assumes all the required directories exist!  */
  275.       }
  276.  
  277.       while  ((nr = read(fd_from, buf, sizeof buf)) > 0 &&
  278.          (nw = write(fd_to, buf, nr)) == nr)
  279.          ;
  280.  
  281.       close(fd_to);
  282.       close(fd_from);
  283.  
  284.       if (nr != 0 || nw == -1)
  285.          return FALSE;        // failed in copy
  286.       return TRUE;
  287. }
  288.  
  289.  
  290. /*--------------------------------------------------------------------*/
  291. /*    C o p y D a t a                                                 */
  292. /*                                                                    */
  293. /*    Copy data into its final resting spot                           */
  294. /*--------------------------------------------------------------------*/
  295.  
  296. static boolean CopyData( const char *input, const char *output)
  297. {
  298.    FILE    *datain;
  299.    FILE    *dataout;
  300.    char     buf[BUFSIZ];
  301.    boolean  status = TRUE;
  302.    size_t   len;
  303.  
  304.    if ( (dataout = FOPEN(output, "w", BINARY_MODE)) == NULL )
  305.    {
  306.       printerr(output);
  307.       printmsg(0,"uux: Cannot open spool file \"%s\" for output",
  308.                output);
  309.       return FALSE;
  310.    }
  311.  
  312. /*--------------------------------------------------------------------*/
  313. /*                      Verify the input opened                       */
  314. /*--------------------------------------------------------------------*/
  315.  
  316.    if (input == NULL)
  317.    {
  318.       datain = stdin;
  319.       setmode(fileno(datain), O_BINARY);   // Don't die on control-Z, etc
  320.    }
  321.    else
  322.       datain = FOPEN(input, "r", BINARY_MODE);
  323.  
  324.    if (datain == NULL) {
  325.       printerr(input);
  326.       printmsg(0,"Unable to open input file \"%s\"",
  327.                (input == NULL ? "stdin" : input));
  328.       fclose(dataout);
  329.       return FALSE;
  330.    } /* datain */
  331.  
  332. /*--------------------------------------------------------------------*/
  333. /*                       Loop to copy the data                        */
  334. /*--------------------------------------------------------------------*/
  335.  
  336.    while ( (len = fread( buf, 1, BUFSIZ, datain)) != 0)
  337.    {
  338.       if ( fwrite( buf, 1, len, dataout ) != len)     // I/O error?
  339.       {
  340.          printerr("dataout");
  341.          printmsg(0,"I/O error on \"%s\"", output);
  342.          fclose(dataout);
  343.          return FALSE;
  344.       } /* if */
  345.    } /* while */
  346.  
  347. /*--------------------------------------------------------------------*/
  348. /*                      Close up shop and return                      */
  349. /*--------------------------------------------------------------------*/
  350.  
  351.    if (ferror(datain))        // Clean end of file on input?
  352.    {
  353.       printerr(input);
  354.       clearerr(datain);
  355.       status = FALSE;
  356.    }
  357.  
  358.    if (input != NULL)
  359.        fclose(datain);
  360.  
  361.    fclose(dataout);
  362.    return status;
  363.  
  364. } /* CopyData */
  365.  
  366. /*--------------------------------------------------------------------*/
  367. /*    s p l i t _ p a t h                                             */
  368. /*--------------------------------------------------------------------*/
  369.  
  370. static boolean split_path(char *path,
  371.                           char *sysname,
  372.                           char *file,
  373.                           boolean expand,
  374.                           char *default_sys )
  375. {
  376.       char *p_left;
  377.       char *p_right;
  378.       char *p = path;
  379.  
  380.       *sysname = *file = '\0';    // init to nothing
  381.  
  382. /*--------------------------------------------------------------------*/
  383. /*                if path is wildcarded then error                    */
  384. /*--------------------------------------------------------------------*/
  385.  
  386.    if (strcspn(path, "*?[") < strlen(path))
  387.    {
  388.       printmsg(0,"uux - Wildcards not allowed in operand: %s",p );
  389.       return FALSE;
  390.    }
  391.  
  392. /*--------------------------------------------------------------------*/
  393. /*                        Find the first bangs                        */
  394. /*--------------------------------------------------------------------*/
  395.  
  396.    p_left = strchr(p, '!');         // look for the first bang
  397.  
  398. /*--------------------------------------------------------------------*/
  399. /*   If no bangs, then the file is on the remote system.  We hope.    */
  400. /*--------------------------------------------------------------------*/
  401.  
  402.    if ( p_left == NULL )
  403.    {
  404.       strcpy( file, p);       // Entire string is file name
  405.  
  406.       strcpy( sysname, default_sys );   // Use default system name
  407.  
  408.       if ( equal(sysname, E_nodename ) &&
  409.            expand &&
  410.            (expand_path(file, NULL, E_homedir, NULL) == NULL))
  411.          return FALSE;     /* expand_path will delivery any needed
  412.                                  nasty-gram to user                  */
  413.  
  414.       return TRUE;
  415.  
  416.    } /* if ( p_left == NULL ) */
  417.  
  418. /*--------------------------------------------------------------------*/
  419. /*                         Find the last bang                         */
  420. /*--------------------------------------------------------------------*/
  421.  
  422.    p_right = strrchr(p, '!');       // look for the last bang
  423.  
  424. /*--------------------------------------------------------------------*/
  425. /*    If the first bang is the first character, it's a local file     */
  426. /*--------------------------------------------------------------------*/
  427.  
  428.       if (p_left == p)                 // First character in path?
  429.       {                                // Yes --> not a remote path
  430.  
  431.          if ( p_left != p_right )      // More bangs?
  432.          {
  433.             printmsg(0,"uux - Invalid syntax for local file: %s", p );
  434.             return FALSE;              // Yes --> I don't grok this
  435.          }
  436.  
  437.          strcpy(file, p+1);            // Just return filename
  438.  
  439.          if ( expand && (expand_path(file, NULL, E_homedir, NULL) == NULL))
  440.             return FALSE;     /* expand_path will delivery any needed
  441.                                  nasty-gram to user                  */
  442.          strcpy(sysname, E_nodename);
  443.          return TRUE;
  444.       } /* p_left == p */
  445.  
  446. /*--------------------------------------------------------------------*/
  447. /*             It's not a local file, continue processing             */
  448. /*--------------------------------------------------------------------*/
  449.  
  450.       strcpy(file, p_right + 1);      // and thats our filename
  451.  
  452.       strncpy(sysname, p, p_left - p); // and we have a system thats not us
  453.       sysname[p_left - p] = '\0';
  454.  
  455. /*--------------------------------------------------------------------*/
  456. /*              Now see if there is an intermediate path              */
  457. /*--------------------------------------------------------------------*/
  458.  
  459.       if (p_left != p_right)
  460.       {
  461.  
  462.           printmsg(0, "uux - Intermediate system %.*s not supported",
  463.                      p_right - (p_left + 1), p_left + 1);
  464.           return FALSE;
  465.  
  466.       } /* if (p_left != p_right) */
  467.  
  468.       return TRUE;                     // and we're done
  469.  
  470. } /* split_path */
  471.  
  472. /*--------------------------------------------------------------------*/
  473. /*    d o _ u u x q t                                                 */
  474. /*                                                                    */
  475. /*    Generate a UUXQT command file for local system                  */
  476. /*--------------------------------------------------------------------*/
  477.  
  478. static boolean do_uuxqt(char *job_name,
  479.                         char *src_syst,
  480.                         char *src_file,
  481.                         char *dest_syst,
  482.                         char *dest_file)
  483. {
  484.    long seqno = 0;
  485.    char *seq  = NULL;
  486.    FILE *stream;              // For writing out data
  487.  
  488.    char msfile[FILENAME_MAX]; // MS-DOS format name of files
  489.    char msname[22];           // MS-DOS format w/o path name
  490.    char ixfile[15];           /* eXecute file for local system,
  491.                                  UNIX format name for local system    */
  492.  
  493. /*--------------------------------------------------------------------*/
  494. /*          Create the UNIX format of the file names we need          */
  495. /*--------------------------------------------------------------------*/
  496.  
  497.    seqno = getseq();
  498.    seq = JobNumber( seqno );
  499.  
  500.    sprintf(ixfile, spool_fmt, 'X', E_nodename, grade , seq);
  501.  
  502. /*--------------------------------------------------------------------*/
  503. /*                     create local X (xqt) file                      */
  504. /*--------------------------------------------------------------------*/
  505.  
  506.    importpath( msname, ixfile, E_nodename);
  507.    mkfilename( msfile, E_spooldir, msname);
  508.  
  509.    if ( (stream = FOPEN(msfile, "w", BINARY_MODE)) == NULL ) {
  510.       printerr(msfile);
  511.       printmsg(0, "uux: cannot open X file %s", msfile);
  512.       return FALSE;
  513.    } /* if */
  514.  
  515.    fprintf(stream, "# third party request, job id\n" );
  516.    fprintf(stream, "J %s\n",               job_name );
  517.    fprintf(stream, "F %s/%s/%s %s\n",      E_spooldir, src_syst, dest_file,
  518.                                           src_file );
  519.    fprintf(stream, "C uucp -C %s %s!%s\n", src_file, dest_syst, dest_file );
  520.    fclose (stream);
  521.  
  522.    return TRUE;
  523.  
  524. } /* do_uuxqt */
  525.  
  526. /*--------------------------------------------------------------------*/
  527. /*    d o _ c o p y                                                   */
  528. /*                                                                    */
  529. /*    At this point only one of the systems can be remote and only    */
  530. /*    1 hop away.  All the rest have been filtered out                */
  531. /*--------------------------------------------------------------------*/
  532.  
  533. static boolean do_copy(char *src_syst,
  534.                        char *src_file,
  535.                        char *dest_syst,
  536.                        char *dest_file)
  537. {
  538.       char    tmfile[25];               // Unix style name for c file
  539.       char    idfile[25];       // Unix style name for data file copy
  540.       char    work[66];             // temp area for filename hacking
  541.       char    icfilename[66];               // our hacked c file path
  542.       char    idfilename[66];               // our hacked d file path
  543.  
  544.       struct  stat    statbuf;
  545.  
  546.       long    int     sequence;
  547.       char    *remote_syst;    // Non-local system in copy
  548.       char    *sequence_s;
  549.       FILE        *cfile;
  550.  
  551.       sequence = getseq();
  552.       sequence_s = JobNumber( sequence );
  553.  
  554.       remote_syst =  equal(src_syst, E_nodename) ? dest_syst : src_syst;
  555.  
  556.       sprintf(tmfile, spool_fmt, 'C', remote_syst, grade, sequence_s);
  557.       importpath(work, tmfile, remote_syst);
  558.       mkfilename(icfilename, E_spooldir, work);
  559.  
  560.       if (!equal(src_syst, E_nodename))
  561.       {
  562.          if (expand_path(dest_file, NULL, E_homedir, NULL) == NULL)
  563.             return FALSE;
  564.  
  565.          SwapSlash(src_file);
  566.  
  567.          printmsg(1, "uux - from \"%s\" - control = %s", src_syst,
  568.                   tmfile);
  569.          if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)  {
  570.             printerr( icfilename );
  571.             printmsg(0, "uux: cannot append to %s\n", icfilename);
  572.             return FALSE;
  573.          }
  574.  
  575.          fprintf(cfile, "R %s %s %s -c D.0 0666", src_file, dest_file,
  576.                   E_mailbox);
  577.  
  578.          if (flags[FLG_USE_USERID])
  579.              fprintf(cfile, " %s\n", user_id);
  580.          else
  581.              fprintf(cfile, " %s\n", E_mailbox);
  582.  
  583.  
  584.          fclose(cfile);
  585.          return TRUE;
  586.       }
  587.       else if (!equal(dest_syst, E_nodename))  {
  588.  
  589.          printmsg(1,"uux - spool %s - execute %s",
  590.                   flags[FLG_COPY_SPOOL] ? "on" : "off",
  591.                   flags[FLG_QUEUE_ONLY] ? "do" : "don't");
  592.          printmsg(1,"     - dest m/c = %s  sequence = %ld  control = %s",
  593.                   dest_syst, sequence, tmfile);
  594.  
  595.          if (expand_path(src_file, NULL, E_homedir, NULL) == NULL)
  596.             return FALSE;
  597.  
  598.          SwapSlash(dest_file);
  599.  
  600.          if (stat(src_file, &statbuf) != 0)  {
  601.             printerr( src_file );
  602.             return FALSE;
  603.          }
  604.  
  605.          if (statbuf.st_mode & S_IFDIR)  {
  606.             printf("uux - directory name \"%s\" illegal\n",
  607.                     src_file );
  608.             return FALSE;
  609.          }
  610.  
  611.          if (flags[FLG_COPY_SPOOL]) {
  612.             sprintf(idfile , dataf_fmt, 'D', E_nodename, sequence_s,
  613.                               subseq());
  614.             importpath(work, idfile, remote_syst);
  615.             mkfilename(idfilename, E_spooldir, work);
  616.  
  617.             /* Do we need a MKDIR here for the system? */
  618.  
  619.             if (!cp(src_file, idfilename))  {
  620.                printmsg(0, "copy \"%s\" to \"%s\" failed",
  621.                   src_file, idfilename);           // copy data
  622.                return FALSE;
  623.             }
  624.          }
  625.          else
  626.             strcpy(idfile, "D.0");
  627.  
  628.          if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL)
  629.          {
  630.             printerr( icfilename );
  631.             printf("uux: cannot append to %s\n", icfilename);
  632.             return FALSE;
  633.          } /* if ((cfile = FOPEN(icfilename, "a",TEXT_MODE)) == NULL) */
  634.  
  635.          fprintf(cfile, "S %s %s %s -%s %s 0666", src_file, dest_file,
  636.                   E_mailbox, flags[FLG_COPY_SPOOL] ? "c" : " ", idfile);
  637.  
  638.          if (flags[FLG_USE_USERID])
  639.              fprintf(cfile, " %s\n", user_id);
  640.          else
  641.              fprintf(cfile, " %s\n", E_mailbox);
  642.  
  643.          fclose(cfile);
  644.  
  645.          return TRUE;
  646.       }
  647.       else {
  648.          if (expand_path(src_file, NULL, E_homedir, NULL) == NULL)
  649.             return FALSE;
  650.  
  651.          if (expand_path(dest_file, NULL, E_homedir, NULL) == NULL)
  652.             return FALSE;
  653.  
  654.          if (strcmp(src_file, dest_file) == 0)
  655.          {
  656.             printmsg(0, "%s %s - same file; can't copy\n",
  657.                   src_file, dest_file);
  658.             return FALSE;
  659.          } /* if (strcmp(src_file, dest_file) == 0) */
  660.  
  661.          return(cp(src_file, dest_file));
  662.       } /* else */
  663. } /* do_copy */
  664.  
  665. /*--------------------------------------------------------------------*/
  666. /*    p r e a m b l e                                                 */
  667. /*                                                                    */
  668. /*    write the execute file preamble based on the global flags       */
  669. /*--------------------------------------------------------------------*/
  670.  
  671. static void preamble(FILE* stream)
  672. {
  673.  
  674.      fprintf(stream, "U %s %s\n", E_mailbox, E_nodename);
  675.  
  676.      if (flags[FLG_RETURN_STDIN]) {
  677.          fprintf(stream, "# return input on abnormal exit\n");
  678.          fprintf(stream, "B\n");
  679.      }
  680.  
  681.      if (flags[FLG_NOTIFY_SUCCESS]) {
  682.          fprintf(stream, "# return status on success\n");
  683.          fprintf(stream, "n\n");
  684.      }
  685.  
  686.      if (flags[FLG_NONOTIFY_FAIL]) {
  687.          fprintf(stream, "# don't return status on failure\n");
  688.          fprintf(stream, "N\n");
  689.      } else {
  690.          fprintf(stream, "# return status on failure\n");
  691.          fprintf(stream, "Z\n");
  692.      }
  693.  
  694.      if (flags[FLG_USE_EXEC]) {
  695.          fprintf(stream, "# use exec to execute\n");
  696.          fprintf(stream, "E\n");
  697.      } else {
  698.          fprintf(stream, "# use sh execute\n");
  699.          fprintf(stream, "e\n");
  700.      }
  701.  
  702.      if (flags[FLG_STATUS_FILE]) {
  703.         fprintf(stream, "M %s\n", st_out );
  704.      }
  705.  
  706.      if (flags[FLG_USE_USERID]) {
  707.          fprintf(stream, "# return address for status or input return\n");
  708.          fprintf(stream, "R %s\n", user_id );
  709.      }
  710.  
  711.      fprintf(stream, "# job id for status reporting\n");
  712.      fprintf(stream, "J %s\n", job_id );
  713.      return;
  714. } /* preamble */
  715.  
  716. /*--------------------------------------------------------------------*/
  717. /*    d o _ r e m o t e                                               */
  718. /*                                                                    */
  719. /*   gather data files to ship to execution system and build X file   */
  720. /*--------------------------------------------------------------------*/
  721.  
  722. static boolean do_remote(int optind, int argc, char **argv)
  723. {
  724.    FILE    *stream;           // For writing out data
  725.    char    *sequence_s;
  726.  
  727.    boolean s_remote;
  728.    boolean d_remote;
  729.    boolean i_remote = FALSE;
  730.    boolean o_remote = FALSE;
  731.  
  732.    long    sequence;
  733.  
  734.    char    src_system[100];
  735.    char    dest_system[100];
  736.    char    src_file[FILENAME_MAX];
  737.    char    dest_file[FILENAME_MAX];
  738.  
  739.    char    command[BUFSIZ];
  740.  
  741.    char    msfile[FILENAME_MAX];    // MS-DOS format name of files
  742.    char    msname[22];              // MS-DOS format w/o path name
  743.  
  744.    char    tmfile[15];        // Call file, UNIX format name
  745.    char    lxfile[15];        /* eXecute file for remote system,
  746.                                  UNIX format name for local system */
  747.    char    rxfile[15];        /* Remote system UNIX name of eXecute
  748.                                  file                              */
  749.    char    lifile[15];        // Data file, UNIX format name
  750.    char    rifile[15];        /* Data file name on remote system,
  751.                                  UNIX format                       */
  752.    char* jobid_fmt = &spool_fmt[3];
  753.  
  754.  
  755. /*--------------------------------------------------------------------*/
  756. /*    Get the remote system and command to execute on that system     */
  757. /*--------------------------------------------------------------------*/
  758.  
  759.    if (!split_path(argv[optind++], dest_system, command, FALSE, E_nodename))
  760.    {
  761.       printmsg(0, "uux - illegal syntax %s", argv[--optind]);
  762.       return FALSE;
  763.    }
  764.  
  765.    d_remote = equal(dest_system, E_nodename) ? FALSE : TRUE ;
  766.  
  767. /*--------------------------------------------------------------------*/
  768. /*        OK - we have a destination system - do we know him?         */
  769. /*--------------------------------------------------------------------*/
  770.  
  771.    if ((d_remote) && (checkreal(dest_system) == BADHOST))
  772.    {
  773.       printmsg(0, "uux - bad system: %s", dest_system);
  774.       return FALSE;
  775.    }
  776.  
  777.    printmsg(9,"xsys -> %s", dest_system);
  778.    printmsg(9, "system \"%s\", rest \"%s\"", dest_system, command);
  779.  
  780.    sequence = getseq();
  781.    sequence_s = JobNumber( sequence );
  782.  
  783.    sprintf(job_id, jobid_fmt, dest_system, grade, sequence_s);
  784.  
  785. /*--------------------------------------------------------------------*/
  786. /*                     create remote X (xqt) file                     */
  787. /*--------------------------------------------------------------------*/
  788.  
  789.       sprintf(rxfile, dataf_fmt, 'X', E_nodename, sequence_s, subseq());
  790.       sprintf(lxfile, dataf_fmt, d_remote ? 'D' : 'X', E_nodename,
  791.               sequence_s, subseq());
  792.  
  793.       importpath( msname, lxfile, dest_system);
  794.       mkfilename( msfile, E_spooldir, msname);
  795.  
  796.       if ( (stream = FOPEN(msfile, "w", BINARY_MODE)) == NULL ) {
  797.          printerr(msfile);
  798.          printmsg(0, "uux: cannot open X file %s", msfile);
  799.          return FALSE;
  800.       } /* if */
  801.  
  802.       preamble(stream);
  803.  
  804. /*--------------------------------------------------------------------*/
  805. /*           Process options for the remote command                   */
  806. /*--------------------------------------------------------------------*/
  807.  
  808.       for (; optind < argc; optind++)
  809.       {
  810.  
  811.          FileType f_remote = DATA_FILE;
  812.          char *remote_file;
  813.  
  814.          switch (*argv[optind])
  815.          {
  816.              case '-':
  817.              strcat(command," ");
  818.              strcat(command,argv[optind]);
  819.              printmsg(9, "prm -> %s", argv[optind]);
  820.              continue;
  821.  
  822.              case '<':
  823.              if (i_remote) {
  824.                  printmsg(0, "uux - multiple input files specified");
  825.                  return FALSE;
  826.              }
  827.              else
  828.                  i_remote = TRUE;
  829.              f_remote = INPUT_FILE;
  830.              printmsg(9, "prm -> %c", *argv[optind]);
  831.              if (!*++argv[optind])
  832.                  if (++optind >= argc)
  833.                  {
  834.                  printmsg(0, "uux - no input file specified after <");
  835.                  return FALSE;
  836.                  }
  837.              break;
  838.  
  839.              case '>':
  840.              if (o_remote) {
  841.                  printmsg(0, "uux - multiple output files specified");
  842.                  return FALSE;
  843.              } else
  844.                  o_remote = TRUE;
  845.              f_remote = OUTPUT_FILE;
  846.              printmsg(9, "prm -> %c", *argv[optind]);
  847.              if (!*++argv[optind])
  848.                  if (++optind >= argc)
  849.                  {
  850.                  printmsg(0, "uux - no output file specified after >");
  851.                  return FALSE;
  852.                  }
  853.              break;
  854.  
  855.              case '|':
  856.              printmsg(9, "prm -> %c", *argv[optind]);
  857.              if (!*++argv[optind])
  858.                  if (++optind >= argc)
  859.                  {
  860.                  printmsg(0, "uux - no command specified after |");
  861.                  return FALSE;
  862.                  }
  863.              if (strchr(argv[optind], '!'))
  864.                  {
  865.                  printmsg(0, "uux - no host name allowed after |");
  866.                  return FALSE;
  867.                  }
  868.              strcat(command," | ");
  869.              strcat(command, argv[optind]);
  870.              continue;
  871.  
  872.              case '(':
  873.              {
  874.                  size_t len = strlen(argv[optind] + 1);
  875.  
  876.                  if (argv[optind][len] != ')')
  877.                  {
  878.                  printmsg(0, "uux - missing close parenthesis in %s",
  879.                          argv[optind] + 1);
  880.                  return FALSE;
  881.                  }
  882.                  argv[optind][len] = '\0';
  883.              }
  884.  
  885.              printmsg(9, "prm -> %s", argv[optind]);
  886.              strcat(command," ");
  887.              strcat(command, argv[optind] + 1);
  888.              continue;
  889.  
  890.              /* default: fall through */
  891.          } /* switch (*argv[optind]) */
  892.  
  893.  
  894.          printmsg(9, "prm -> %s", argv[optind]);
  895.  
  896. /*--------------------------------------------------------------------*/
  897. /*        Hmmm.  Do we want the remote to have DOS style path?        */
  898. /*--------------------------------------------------------------------*/
  899.  
  900.          if (!split_path(argv[optind], src_system, src_file, FALSE, dest_system))
  901.          {
  902.             printmsg(0, "uux - illegal syntax %s", argv[optind]);
  903.             return FALSE;
  904.          } /* if (!split_path()) */
  905.  
  906.          s_remote = equal(src_system, E_nodename) ? FALSE : TRUE ;
  907.  
  908. /*--------------------------------------------------------------------*/
  909. /*                   Do we know the source system?                    */
  910. /*--------------------------------------------------------------------*/
  911.  
  912.          if ((s_remote) && (checkreal(src_system) == BADHOST))
  913.          {
  914.             printmsg(0, "uux - bad system %s\n", src_system);
  915.             return FALSE;
  916.          } /* if ((s_remote) && (checkreal(src_system) == BADHOST)) */
  917.  
  918.          if (f_remote == OUTPUT_FILE)
  919.          {
  920.             fprintf(stream, "O %s %s\n", src_file,
  921.                 (equal(src_system, dest_system) ? " " : src_system) );
  922.             continue;
  923.          } /* if (f_remote == OUTPUT_FILE) */
  924.  
  925.          remote_file = src_file;
  926.          if (!equal(src_system, dest_system))
  927.          {
  928.              remote_file += strlen(src_file);
  929.              while (remote_file > src_file  // Keep trailing / and :
  930.              && (*--remote_file == '/'
  931.                  /* || *remote_file == '\\' */
  932.                  || *remote_file == ':'))
  933.             ;
  934.              while (remote_file > src_file  // Stop at other / and :
  935.                 && remote_file[-1] != '/'
  936.                 /* && remote_file[-1] != '\\' */
  937.                 && remote_file[-1] != ':')
  938.             --remote_file;
  939.              /* remote_file is now src_file without any leading drive/path */
  940.         } /* if (!equal(src_system, dest_system)) */
  941.  
  942.         if (f_remote == DATA_FILE)
  943.         {
  944.  
  945.            strcat(command, " ");
  946.            strcat(command, remote_file);
  947.  
  948.         } /* if (f_remote == DATA_FILE) */
  949.         else if (f_remote == INPUT_FILE)
  950.            fprintf(stream, "I %s\n", remote_file);
  951.  
  952. /*--------------------------------------------------------------------*/
  953. /*    if both source & dest are not the same we must copy src_file    */
  954. /*--------------------------------------------------------------------*/
  955.  
  956.          if ( !equal(src_system, dest_system) )
  957.          {
  958.  
  959.             sprintf(dest_file, dataf_fmt, 'D', src_system, sequence_s,
  960.                     subseq());
  961.  
  962.             fprintf(stream, "F %s %s\n", dest_file, remote_file );
  963.  
  964. /*--------------------------------------------------------------------*/
  965. /*      if source is remote and dest is local copy source to local    */
  966. /*      if source is local and dest is remote copy source to remote   */
  967. /*--------------------------------------------------------------------*/
  968.  
  969.             if ((s_remote && !d_remote) || (!s_remote && d_remote))
  970.             {
  971.                if (!do_copy(src_system, src_file, dest_system, dest_file))
  972.                    return FALSE;
  973.             } /* if ((s_remote && !d_remote) || (!s_remote && d_remote)) */
  974.  
  975. /*--------------------------------------------------------------------*/
  976. /*      if both source & dest are on remote nodes we need uuxqt       */
  977. /*--------------------------------------------------------------------*/
  978.  
  979.             else if (s_remote && d_remote)
  980.             {
  981.                if (!do_uuxqt(job_id,
  982.                              src_system,
  983.                              remote_file,
  984.                              dest_system,
  985.                              dest_file))
  986.                    return FALSE;
  987.  
  988.                if (!do_copy(src_system, src_file, E_nodename, dest_file))
  989.                    return FALSE;
  990.  
  991.             } /* else if (s_remote && d_remote) */
  992.  
  993.             continue;
  994.          } /* if ( !equal(src_system, dest_system) ) */
  995.  
  996.          printmsg(4, "system \"%s\", rest \"%s\"", src_system, src_file);
  997.  
  998.       } /* for (; optind < argc; optind++) */
  999.  
  1000. /*--------------------------------------------------------------------*/
  1001. /*  Create the data file if any to send to the remote system          */
  1002. /*--------------------------------------------------------------------*/
  1003.  
  1004.       if (flags[FLG_READ_STDIN]) {
  1005.           if (i_remote) {
  1006.               printmsg(0, "uux - multiple input files specified");
  1007.               return FALSE;
  1008.           }
  1009.  
  1010.           sprintf(rifile, dataf_fmt, 'D', E_nodename, sequence_s,
  1011.                   subseq());
  1012.           sprintf(lifile, dataf_fmt, 'D', E_nodename, sequence_s,
  1013.                   subseq());
  1014.  
  1015.           importpath(msname, lifile, dest_system);
  1016.           mkfilename(msfile, E_spooldir, msname);
  1017.  
  1018.           if (!CopyData( NULL, msfile )) {
  1019.               remove( msfile );
  1020.               return FALSE;
  1021.           }
  1022.  
  1023.           fprintf(stream, "F %s\n", rifile);
  1024.           fprintf(stream, "I %s\n", rifile);
  1025.       }
  1026.  
  1027. /*--------------------------------------------------------------------*/
  1028. /*           here finish writing parameters to the X file             */
  1029. /*--------------------------------------------------------------------*/
  1030.  
  1031.       printmsg(4, "command \"%s\"", command);
  1032.  
  1033.  
  1034.       fprintf(stream, "C %s\n", command);
  1035.       fclose(stream);
  1036.  
  1037. /*--------------------------------------------------------------------*/
  1038. /*                     create local C (call) file                     */
  1039. /*--------------------------------------------------------------------*/
  1040.  
  1041.      if (d_remote) {
  1042.           sprintf(tmfile, spool_fmt, 'C', dest_system,  grade, sequence_s);
  1043.           importpath( msname, tmfile, dest_system);
  1044.           mkfilename( msfile, E_spooldir, msname);
  1045.  
  1046.           if ( (stream = FOPEN(msfile, "a",TEXT_MODE)) == NULL) {
  1047.              printerr( msname );
  1048.              printmsg(0, "uux: cannot write/append to C file %s", msfile);
  1049.              return FALSE;
  1050.           }
  1051.  
  1052.           if (flags[FLG_READ_STDIN])
  1053.               fprintf(stream, send_cmd, lifile, rifile, E_mailbox, lifile);
  1054.  
  1055.           fprintf(stream, send_cmd, lxfile, rxfile, E_mailbox, lxfile);
  1056.  
  1057.           fclose(stream);
  1058.      }
  1059.      return TRUE;
  1060. } /* do_remote */
  1061.  
  1062. /*--------------------------------------------------------------------*/
  1063. /*    m a i n                                                         */
  1064. /*                                                                    */
  1065. /*    main program                                                    */
  1066. /*--------------------------------------------------------------------*/
  1067.  
  1068. void main(int  argc, char  **argv)
  1069. {
  1070.    int         c;
  1071.    extern char *optarg;
  1072.    extern int   optind;
  1073.  
  1074. /*--------------------------------------------------------------------*/
  1075. /*     Report our version number and date/time compiled               */
  1076. /*--------------------------------------------------------------------*/
  1077.  
  1078.    debuglevel = 0;
  1079.    banner( argv );
  1080.  
  1081. #if defined(__CORE__)
  1082.    copywrong = strdup(copyright);
  1083.    checkref(copywrong);
  1084. #endif
  1085.  
  1086.    if (!configure( B_UUCP ))
  1087.       exit(1);   /* system configuration failed */
  1088.  
  1089.    user_id = E_mailbox;
  1090.  
  1091. /*--------------------------------------------------------------------*/
  1092. /*        Process our arguments                                       */
  1093. /*--------------------------------------------------------------------*/
  1094.  
  1095. /*--------------------------------------------------------------------*
  1096.  *
  1097.  *   -aname    Use name as the user identification replacing the initiator
  1098.  *   -b        Return whatever standard input was provided to the uux command
  1099.  *   -c        Do not copy local file to the spool directory for transfer to
  1100.  *   -C        Force the copy of local files to the spool directory for
  1101.  *   -E        run job using exec
  1102.  *   -e        run job using sh
  1103.  *   -ggrade   Grade is a single letter number; lower ASCII sequence
  1104.  *   -j        Output the jobid ASCII string on the standard output which is
  1105.  *   -n        Do not notify the user if the command fails.
  1106.  *   -p        Same as -:  The standard input to uux is made the standard
  1107.  *   -r        Do not start the file transfer, just queue the job.
  1108.  *   -sfile    Report status of the transfer in file.
  1109.  *   -xdebug_level
  1110.  *   -z        Send success notification to the user.
  1111.  *
  1112. /*--------------------------------------------------------------------*/
  1113.  
  1114.    while ((c = getopt(argc, argv, "-a:bcCEejg:nprs:x:z")) !=  EOF)
  1115.       switch(c) {
  1116.       case '-':
  1117.          flags[FLG_READ_STDIN] = TRUE;
  1118.          break;
  1119.       case 'a':
  1120.          flags[FLG_USE_USERID] = TRUE;
  1121.          user_id = optarg;
  1122.          break;
  1123.       case 'b':
  1124.          flags[FLG_RETURN_STDIN] = TRUE;
  1125.          break;
  1126.       case 'c':               // don't spool
  1127.          flags[FLG_COPY_SPOOL] = FALSE;
  1128.          break;
  1129.       case 'C':               // force spool
  1130.          flags[FLG_COPY_SPOOL] = TRUE;
  1131.          break;
  1132.       case 'E':               // use exec to execute
  1133.          flags[FLG_USE_EXEC] = TRUE;
  1134.          break;
  1135.       case 'e':               // use sh to execute
  1136.          flags[FLG_USE_EXEC] = FALSE;
  1137.          break;
  1138.       case 'j':               // output job id to stdout
  1139.          flags[FLG_OUTPUT_JOBID] = TRUE;
  1140.          break;
  1141.       case 'n':               // do not notify user if command fails
  1142.          flags[FLG_NONOTIFY_FAIL] = TRUE;
  1143.          break;
  1144.       case 'p':
  1145.          flags[FLG_READ_STDIN] = TRUE;
  1146.          break;
  1147.       case 'r':               // queue job only
  1148.          flags[FLG_QUEUE_ONLY] = TRUE;
  1149.          break;
  1150.       case 'z':
  1151.          flags[FLG_NOTIFY_SUCCESS] = TRUE;
  1152.          break;
  1153.       case 'g':               // set grade of transfer
  1154.          grade = *optarg;
  1155.          break;
  1156.       case 's':               // report status of transfer to file
  1157.          flags[FLG_STATUS_FILE] = TRUE;
  1158.          st_out = optarg;
  1159.          break;
  1160.       case 'x':
  1161.          debuglevel = atoi( optarg );
  1162.          break;
  1163.       case '?':
  1164.          usage();
  1165.          exit(1);
  1166.          break;
  1167.       default:
  1168.          printmsg(0, "uux - bad argument from getopt \"%c\"", c);
  1169.          exit(1);
  1170.          break;
  1171.    }
  1172.  
  1173.    if (argc - optind < 1)     // Verify we have at least a command
  1174.    {
  1175.       printmsg(0,"uux - no command to execute!");
  1176.       usage();
  1177.       exit(1);
  1178.    }
  1179.  
  1180. #if defined(_Windows)
  1181.    openlog( NULL );
  1182.    atexit( CloseEasyWin );               // Auto-close EasyWin on exit
  1183. #endif
  1184.  
  1185.    if (!do_remote(optind, argc, argv))
  1186.    {
  1187.       printmsg(0, "uux command failed");
  1188.       exit(1);
  1189.    };
  1190.  
  1191.    if (flags[FLG_OUTPUT_JOBID])
  1192.        printf("%s\n", job_id);
  1193.  
  1194.    exit(0);
  1195. } /* main */
  1196.  
  1197. /*--------------------------------------------------------------------*/
  1198. /*    s u b s e q                                                    */
  1199. /*                                                                    */
  1200. /*    Generate a valid sub-sequence number                            */
  1201. /*--------------------------------------------------------------------*/
  1202.  
  1203. static char subseq( void )
  1204. {
  1205.    static char next = '0' - 1;
  1206.  
  1207.    switch( next )
  1208.    {
  1209.       case '9':
  1210.          next = 'A';
  1211.          break;
  1212.  
  1213.       case 'Z':
  1214.          next = 'a';
  1215.          break;
  1216.  
  1217.       default:
  1218.          next += 1;
  1219.    } /* switch */
  1220.  
  1221.    return next;
  1222.  
  1223. } /* subseq */
  1224.